import numpy as np
import pandas as pd
from typing import Union, List, Optional


def calculate_percentile(data: Union[pd.Series, List, np.ndarray], percentile: float = 50) -> float:
    """
    计算数据的百分位数
    
    Args:
        data: 输入数据，可以是pandas Series、列表或numpy数组
        percentile: 百分位数，范围0-100，默认50（中位数）
    
    Returns:
        计算得到的百分位数值
    """
    if len(data) == 0:
        return np.nan
    
    # 移除NaN值
    clean_data = pd.Series(data).dropna()
    if len(clean_data) == 0:
        return np.nan
    
    return np.percentile(clean_data, percentile)


def calculate_rolling_percentile(data: Union[pd.Series, List, np.ndarray], 
                                window: int = 30, 
                                percentile: float = 50) -> pd.Series:
    """
    计算滚动百分位数
    
    Args:
        data: 输入数据
        window: 滚动窗口大小，默认30
        percentile: 百分位数，范围0-100，默认50（中位数）
    
    Returns:
        滚动百分位数序列
    """
    series = pd.Series(data)
    return series.rolling(window=window, min_periods=1).quantile(percentile / 100)


def calculate_historical_percentile(value: float, 
                                   historical_data: Union[pd.Series, List, np.ndarray]) -> float:
    """
    计算某个值在历史数据中的百分位数位置
    
    Args:
        value: 要计算百分位数位置的值
        historical_data: 历史数据
    
    Returns:
        该值在历史数据中的百分位数位置（0-100）
    """
    if len(historical_data) == 0:
        return np.nan
    
    # 移除NaN值
    clean_data = pd.Series(historical_data).dropna()
    if len(clean_data) == 0:
        return np.nan
    
    # 计算小于等于该值的数据点占比
    return (clean_data <= value).mean() * 100


def calculate_percentile_bands(data: Union[pd.Series, List, np.ndarray], 
                              percentiles: List[float] = [25, 50, 75]) -> dict:
    """
    计算多个百分位数，常用于绘制百分位数带状图
    
    Args:
        data: 输入数据
        percentiles: 百分位数列表，默认[25, 50, 75]
    
    Returns:
        包含各百分位数的字典
    """
    if len(data) == 0:
        return {f'p{p}': np.nan for p in percentiles}
    
    clean_data = pd.Series(data).dropna()
    if len(clean_data) == 0:
        return {f'p{p}': np.nan for p in percentiles}
    
    return {f'p{p}': np.percentile(clean_data, p) for p in percentiles}


def calculate_percentile_rank_series(data: Union[pd.Series, List, np.ndarray], 
                                    window: Optional[int] = None) -> pd.Series:
    """
    计算数据序列中每个点的百分位数排名
    
    Args:
        data: 输入数据序列
        window: 可选的滚动窗口大小，如果指定则计算滚动百分位数排名
    
    Returns:
        百分位数排名序列（0-100）
    """
    series = pd.Series(data)
    
    if window is None:
        # 计算全期百分位数排名
        return series.rank(pct=True) * 100
    else:
        # 计算滚动百分位数排名
        def rolling_rank(x):
            if len(x.dropna()) == 0:
                return np.nan
            return (x.dropna() <= x.iloc[-1]).mean() * 100
        
        return series.rolling(window=window, min_periods=1).apply(rolling_rank, raw=False)